Skip to content

Subsystem 2a-ii: oil-rig activation detection (small/large) via CH47 + 3-state machine + #events/in-game alerts + /small //large - #14

Merged
HandyS11 merged 11 commits into
developfrom
feat/oilrig-events
Jun 17, 2026
Merged

Subsystem 2a-ii: oil-rig activation detection (small/large) via CH47 + 3-state machine + #events/in-game alerts + /small //large#14
HandyS11 merged 11 commits into
developfrom
feat/oilrig-events

Conversation

@HandyS11

Copy link
Copy Markdown
Owner

Summary

Implements small/large oil-rig activation detection — the CH47 workaround deferred out of 2a. Since the current Rust game no longer sends locked-crate map markers, rig status is inferred from CH47 (Chinook) movement: a CH47 entering an oil-rig monument's radius marks that rig as activated.

This is the second slice of subsystem 2 (live events). Builds on 2a (#13).

What it does

  • Detection (ConnectionSupervisor): fetches rig monuments once on connect (oilrig_1 = small, large_oil_rig = large), and on each marker poll fires a rig-activation event when a CH47 enters a rig's radius (debounced once per visit). Marker poll cadence is now adaptive — 5s base, 2s while a CH47 is live (to catch the brief at-rig visit). The existing cargo/heli/chinook marker path is unchanged; the generic "Chinook spawned" event still fires alongside a rig activation.
  • State machine (RigStateStore, in-memory, per (guild, server, rig)): Online (armed, assumed on connect) → CH47 → Active (combat phase, ~15m) → Offline (crate lootable/looted, ~15m) → Online. A 30s background tick advances the two timed boundaries.
  • Alerts: all three rig boundaries (activated / crate-lootable / respawned) post a localized embed to #events and broadcast a localized in-game team-chat line. The in-game broadcast was generalized to every live event (cargo/heli/chinook too, 1:1 with #events).
  • Surfaces: !small / !large in-game commands + /small / /large slash commands report rig status + time remaining.

All configurable: RigRadius (150), RigActiveWindow / RigOfflineWindow (15m), RigTickInterval (30s), MarkerPollInterval (5s) / MarkerPollFastInterval (2s).

Scope notes

  • No new entity / migration / persistence / project / gateway intent — all in-memory (mirrors 2a).
  • EN/FR localized throughout.
  • The timed Online→Offline transition is unobservable, so it's a best-effort timer; rig state is a best-effort inference, re-synced on the next real CH47 activation.

Tests & quality

  • Build 0 warnings / 0 errors (strict analyzers).
  • 321 tests green across 8 assemblies (+25 vs base): Abstractions 9, Events 43, Commands 98, Connections 32, + Chat/Workspace/Pairing/Persistence unchanged.
  • jb ReformatAndReorder clean; no EF model drift.
  • Built subagent-driven (per-task TDD + per-task spec/quality review + a final whole-branch review = ready to merge).

🤖 Generated with Claude Code

HandyS11 and others added 10 commits June 17, 2026 19:49
…angedEvent

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ive poll cadence

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 17, 2026 19:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements subsystem 2a-ii oil-rig lifecycle detection and alerting by inferring rig activation from CH47 movement near monument coordinates, then driving a 3-state in-memory rig state machine and broadcasting alerts to both Discord #events and in-game team chat. This extends the existing live-events marker poller and command surface added in 2a.

Changes:

  • Add CH47→oil-rig activation detection (small/large) with adaptive marker polling and monument lookup on connect.
  • Introduce an in-memory rig state machine + periodic tick to emit timed boundaries (crate lootable / respawned).
  • Add rig status commands (!small/!large and /small//large) plus generalized in-game broadcasts for all live events.

Reviewed changes

Copilot reviewed 35 out of 35 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/RustPlusBot.Features.Events.Tests/State/RigStateStoreTests.cs Adds unit coverage for rig state transitions and timers.
tests/RustPlusBot.Features.Events.Tests/Rendering/RigRenderingTests.cs Adds tests for rig embed + in-game line rendering.
tests/RustPlusBot.Features.Events.Tests/Relaying/EventRelayTests.cs Extends relay tests for in-game broadcasts and rig relaying behavior.
tests/RustPlusBot.Features.Events.Tests/Hosting/EventsHostedServiceTickTests.cs Adds test for the rig-timer tick publishing boundary events.
tests/RustPlusBot.Features.Events.Tests/EventRegistrationTests.cs Updates DI registration test setup for new rig/broadcast dependencies.
tests/RustPlusBot.Features.Connections.Tests/Fakes/FakeRustSocketSource.cs Adds monuments support to the fake socket connection for supervisor tests.
tests/RustPlusBot.Features.Connections.Tests/ConnectionSupervisorTests.cs Adds integration-style tests for CH47 entering/leaving rig radius.
tests/RustPlusBot.Features.Connections.Tests/ConnectionOptionsTests.cs Verifies new ConnectionOptions defaults (poll cadence, rig windows/radius).
tests/RustPlusBot.Features.Commands.Tests/Handlers/RigCommandHandlersTests.cs Adds tests for !small/!large command replies.
tests/RustPlusBot.Features.Commands.Tests/CommandRegistrationTests.cs Updates command registration tests for new rig handlers and IRigState.
tests/RustPlusBot.Abstractions.Tests/Events/RigStateChangedEventTests.cs Adds tests for new rig event and monument snapshot DTOs.
src/RustPlusBot.Host/Program.cs Adds startup validation for new rig and fast-poll options.
src/RustPlusBot.Features.Events/State/RigStatus.cs Introduces rig lifecycle status enum (Online/Active/Offline).
src/RustPlusBot.Features.Events/State/RigStateStore.cs Implements the in-memory rig state machine with timer advancement.
src/RustPlusBot.Features.Events/State/RigState.cs Adds a value type for point-in-time rig state reads.
src/RustPlusBot.Features.Events/State/IRigState.cs Adds rig state read interface for commands and other consumers.
src/RustPlusBot.Features.Events/Rendering/EventLocalizationCatalog.cs Adds localized strings for rig events and in-game “.line” variants.
src/RustPlusBot.Features.Events/Rendering/EventEmbedRenderer.cs Adds rig embed + rig line rendering; adds in-game rendering for other events.
src/RustPlusBot.Features.Events/Relaying/EventRelay.cs Relays events to Discord + in-game team chat; applies rig activation events to state.
src/RustPlusBot.Features.Events/Hosting/EventsHostedService.cs Adds rig event consumer loop + rig tick loop; clears rig state on disconnect.
src/RustPlusBot.Features.Events/EventServiceCollectionExtensions.cs Registers RigStateStore / IRigState in DI.
src/RustPlusBot.Features.Connections/Supervisor/ConnectionSupervisor.cs Fetches monuments on connect, detects rig activation during marker polling, adds adaptive poll cadence.
src/RustPlusBot.Features.Connections/Listening/RustPlusSocketSource.cs Implements GetMonumentsAsync via Rust+ GetMap.
src/RustPlusBot.Features.Connections/Listening/IRustServerConnection.cs Extends connection contract with GetMonumentsAsync.
src/RustPlusBot.Features.Connections/ConnectionOptions.cs Adds rig-related config and fast marker poll interval; updates poll default to 5s.
src/RustPlusBot.Features.Commands/Modules/ServerCommandModule.cs Adds /small and /large slash commands.
src/RustPlusBot.Features.Commands/Localization/CommandLocalizationCatalog.cs Adds EN/FR localized responses for rig status commands.
src/RustPlusBot.Features.Commands/Handlers/SmallCommandHandler.cs Implements !small command handler.
src/RustPlusBot.Features.Commands/Handlers/RigReply.cs Adds shared formatting logic for rig status replies.
src/RustPlusBot.Features.Commands/Handlers/LargeCommandHandler.cs Implements !large command handler.
src/RustPlusBot.Features.Commands/CommandServiceCollectionExtensions.cs Registers new rig command handlers.
src/RustPlusBot.Abstractions/Events/RigStateChangedEvent.cs Adds event contract for rig lifecycle boundaries.
src/RustPlusBot.Abstractions/Events/RigKind.cs Adds small/large rig enum.
src/RustPlusBot.Abstractions/Events/RigEventKind.cs Adds rig boundary kind enum (Activated/Lootable/Respawned).
src/RustPlusBot.Abstractions/Connections/MonumentSnapshot.cs Adds monument DTO used to locate rigs via GetMap.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +53 to +55
// Transfer any pre-staged monuments so they are available before the supervisor fetches them on connect.
connection.MonumentsResult = _pendingMonuments;

Comment on lines +71 to +79
public void Apply(RigStateChangedEvent activated)
{
ArgumentNullException.ThrowIfNull(activated);
var key = (activated.GuildId, activated.ServerId, activated.Rig);
lock (Gate)
{
_rigs[key] = new Entry(RigStatus.Active, clock.UtcNow, activated.X, activated.Y, activated.Dimensions);
}
}
Comment on lines +527 to +533
#pragma warning disable CA1031 // Broad catch: a monuments-fetch failure just disables rig detection this window.
catch (Exception ex)
#pragma warning restore CA1031
{
LogMarkerPollFailed(logger, ex,
Guid.Empty); // reuse the marker-poll-failed log; rig detection degrades gracefully
return [];
Comment thread tests/RustPlusBot.Features.Events.Tests/State/RigStateStoreTests.cs
Comment on lines +1 to +4
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using NSubstitute;
Comment on lines +1 to +4
using RustPlusBot.Abstractions.Events;
using RustPlusBot.Features.Connections.Listening;
using RustPlusBot.Features.Events.Classifying;
using RustPlusBot.Features.Events.Rendering;
- FakeRustSocketSource: reset _pendingMonuments after transfer in Create() so
  SetMonuments applies to the NEXT connection only (no cross-connection leak /
  test order-dependence).
- RigStateStore.Apply: fail-fast ArgumentException when Kind != Activated (the
  timed kinds come from Advance, not Apply); add a Theory covering both.
- ConnectionSupervisor: dedicated LogMonumentsFetchFailed message threading the
  real server id (was misattributed to LogMarkerPollFailed with Guid.Empty).
- Remove genuinely-unused usings (NSubstitute + Connections.Listening in
  RigStateStoreTests; Connections.Listening in RigRenderingTests). Kept the
  usings Copilot flagged that are actually in use (M.E.DependencyInjection for
  IServiceScopeFactory in the tick test; Classifying for RustMapEvent/MapEventKind).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HandyS11

Copy link
Copy Markdown
Owner Author

Addressed the Copilot review in fcb3041:

  • FakeRustSocketSource monument leak — fixed: _pendingMonuments is now reset to [] after transfer in Create(), so SetMonuments applies to the next connection only (no cross-connection leak / order-dependence).
  • RigStateStore.Apply not enforcing Activated — fixed: now throws ArgumentException when Kind != Activated (the timed kinds are produced by Advance, not applied here), with a [Theory] covering CrateLootable/Respawned.
  • Misleading monuments-fetch failure log — fixed: a dedicated LogMonumentsFetchFailed message now threads the real serverId (was reusing LogMarkerPollFailed with Guid.Empty).
  • Unused usings — removed the genuinely-unused ones: NSubstitute + RustPlusBot.Features.Connections.Listening in RigStateStoreTests, and RustPlusBot.Features.Connections.Listening in RigRenderingTests.
    • Two of the flagged usings are actually in use, so they were kept (removing them would break the strict build): Microsoft.Extensions.DependencyInjection in EventsHostedServiceTickTests provides IServiceScopeFactory, and RustPlusBot.Features.Events.Classifying in RigRenderingTests provides RustMapEvent/MapEventKind.

Build 0/0 strict, jb-clean, full suite green (323 tests across 8 assemblies).

@HandyS11
HandyS11 merged commit 026b585 into develop Jun 17, 2026
3 checks passed
@HandyS11
HandyS11 deleted the feat/oilrig-events branch June 17, 2026 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants